package com.doctcloud.common.elasticsearch.config;

import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import org.apache.http.HttpHost;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.elasticsearch.client.HttpAsyncResponseConsumerFactory;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;

/**
 * Elasticsearch 客户端配置类（带认证和合理资源配置）
 *
 * @author samula
 */
@Configuration
@AutoConfigureBefore(ElasticsearchRestClientAutoConfiguration.class)
public class ElasticSearchConfig {

    @Value("${elasticsearch.host:127.0.0.1}")
    private String elasticsearchHost;

    @Value("${elasticsearch.port:9200}")
    private int elasticsearchPort;

    @Value("${elasticsearch.scheme:http}")
    private String elasticsearchScheme;

    // 静态字段存储认证令牌
    private static String elasticsearchToken;

    // 通过setter方法注入值（Spring会自动调用）
    @Value("${elasticsearch.token:}")
    public void setElasticsearchToken(String token) {
        ElasticSearchConfig.elasticsearchToken = token;
    }

    // 定义公共请求选项（带认证和合理资源配置）
    private static final RequestOptions COMMON_OPTIONS;
    static {
        RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
        // 添加认证头
        if (elasticsearchToken != null && !elasticsearchToken.isEmpty()) {
            builder.addHeader("Authorization", "Bearer " + elasticsearchToken);
        }
        // 设置合理的响应缓冲区大小（10MB）
        // 正确用法：直接使用具体实现类 HeapBufferedResponseConsumerFactory
        builder.setHttpAsyncResponseConsumerFactory(
                new HttpAsyncResponseConsumerFactory.HeapBufferedResponseConsumerFactory(10 * 1024 * 1024)
        );
        COMMON_OPTIONS = builder.build();
    }

    /**
     * 创建低级别的 RestClient
     */
    @Bean(destroyMethod = "close")
    public RestClient restClient() {
        return RestClient.builder(
                        new HttpHost(elasticsearchHost, elasticsearchPort, elasticsearchScheme)
                )
                .setRequestConfigCallback(requestConfigBuilder ->
                        requestConfigBuilder
                                .setConnectTimeout(5000)     // 连接超时 5秒
                                .setSocketTimeout(30000)    // 套接字超时 30秒
                                .setConnectionRequestTimeout(5000) // 连接请求超时 1秒
                )
                .setHttpClientConfigCallback(httpClientBuilder -> {
                    // 配置连接池参数（使用 org.apache.hc.core5.http.config.IOReactorConfig）
                    httpClientBuilder.setDefaultIOReactorConfig(
                            IOReactorConfig.custom()
                                    .setIoThreadCount(Runtime.getRuntime().availableProcessors() * 2)
                                    .build()
                    );
                    return httpClientBuilder;
                })
                .build();
    }

    /**
     * 创建 Transport 对象
     */
    @Bean
    public RestClientTransport transport(RestClient restClient) {
//        return new RestClientTransport(
//                restClient, new JacksonJsonpMapper()
//        );
        // 1. 配置 JsonFactory（不直接设置编码，通过 ObjectMapper 统一控制）
        JsonFactory jsonFactory = new JsonFactory();
        // 仅保留必要的 JSON 解析配置（解决字段名无引号的场景，可选）
        jsonFactory.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

        // 2. 配置 ObjectMapper，强制 UTF-8 编码并支持时间类型
        ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
        // 核心：设置 JSON 序列化/反序列化的默认编码为 UTF-8
        objectMapper.findAndRegisterModules() // 自动注册所有 Jackson 模块（含 JavaTimeModule）
                .configure(com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT, false); // 关闭格式化输出（非必需）

        // 3. 构建 Elasticsearch 客户端专用的 JsonpMapper
        JacksonJsonpMapper jsonpMapper = new JacksonJsonpMapper(objectMapper);

        // 4. 创建 RestClientTransport 并返回
        return new RestClientTransport(restClient, jsonpMapper);
    }

    /**
     * 创建高级别的 ElasticsearchClient
     */
    @Bean
    public co.elastic.clients.elasticsearch.ElasticsearchClient elasticsearchClient(RestClientTransport transport) {
        return new co.elastic.clients.elasticsearch.ElasticsearchClient(transport);
    }

    /**
     * 暴露公共请求选项，供业务代码使用
     */
    @Bean
    public RequestOptions commonRequestOptions() {
        return COMMON_OPTIONS;
    }
}